#include "../include/logger.h"
#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <sys/time.h>
#include <assert.h>
#include <cerrno>
#include <sys/stat.h>

namespace util {

// LogBuffer实现
LogBuffer::LogBuffer(size_t size)
    : _data(new char[size]),
    _capacity(size),
    _current(_data) 
{
    memset(_data, 0, size);  // 初始化缓冲区内存
}

LogBuffer::~LogBuffer() 
{
    delete[] _data;  // 释放缓冲区内存
}

bool LogBuffer::append(const char* data, size_t len) 
{
    // 检查输入有效性
    if (!data || len == 0) return false;

    // 检查缓冲区是否有足够空间
    if (len <= avail()) 
    {
        memcpy(_current, data, len);  // 复制数据到缓冲区
        _current += len;  // 更新当前写入位置
        return true;
    }
    return false;  // 缓冲区已满
}

// AsyncLogging实现
AsyncLogging::AsyncLogging(const std::string& basename, size_t rollSize, int flushInterval)
    : _basename(basename),
      _rollSize(rollSize),
      _flushInterval(flushInterval),
      _running(false),
      _flushRequest(false),
      _currentBuffer(new LogBuffer(4 * 1024 * 1024)),   // 4MB缓冲区
      _nextBuffer(new LogBuffer(4 * 1024 * 1024))       // 4MB预备缓冲区
{    
    _buffers.reserve(16);  // 预分配刷盘缓冲区空间
}

AsyncLogging::~AsyncLogging() 
{
    if (_running) 
    {
        stop();  // 确保在析构时停止日志线程
    }
}

void AsyncLogging::start() 
{   
    if (!_running) 
    {
        _running = true;
        _thread = std::thread(&AsyncLogging::threadFunc, this);  // 启动后端线程
    }
}

void AsyncLogging::stop() 
{
    if (_running) 
    {
        _running = false;
        _cond.notify_one();  // 唤醒可能在等待的线程
        if (_thread.joinable()) 
        {
            _thread.join();  // 等待线程结束
        }
    }
}

// 前端多线程调用，需加锁保护共享缓冲区
void AsyncLogging::append(const char* logline, int len) 
{
    // 检查输入有效性
    if (!logline || len <= 0) return;

    std::lock_guard<std::mutex> lock(_mutex);
    
    // 当前缓冲区有足够空间，直接写入
    if (len <= _currentBuffer->avail()) 
    {
        _currentBuffer->append(logline, len);
    } 
    else 
    {
        // 当前缓冲区已满，将其加入待写入队列
        _buffers.emplace_back(std::move(_currentBuffer));
        
        // 使用预备缓冲区（如果有）
        if (_nextBuffer) 
        {
            _currentBuffer = std::move(_nextBuffer);
        } 
        else 
        {
            // 没有预备缓冲区，创建新的
            _currentBuffer.reset(new LogBuffer(4*1024*1024));
        }
        
        // 写入新数据
        _currentBuffer->append(logline, len);
        
        // 通知后端线程有数据需要写入
        _cond.notify_one();
    }
}

void AsyncLogging::forceFlush() 
{
    std::unique_lock<std::mutex> lock(_mutex);
        
    // 如果当前缓冲区有数据，将其加入待处理队列
    if (_currentBuffer->length() > 0) 
    {
        _buffers.emplace_back(std::move(_currentBuffer));
        _currentBuffer.reset(new LogBuffer(4 * 1024 * 1024));
    }
        
    // 设置刷新请求标志
    _flushRequest = true;
        
    // 唤醒后端线程
    _cond.notify_one();
        
    // 等待刷新完成
    _flushCond.wait(lock, [this]() {
        return _flushRequest == false; });
}

// 生成带时间戳的日志文件名 server_log.20250712-143025.12345.log
static std::string getLogFileName(const std::string& basename, time_t* now) 
{
    std::string filename;
    filename.reserve(basename.size() + 64);
    filename = basename;
    
    char timebuf[32];
    struct tm tm;
    *now = time(nullptr);
    localtime_r(now, &tm);  // 使用本地时间，与日志内容时间一致
    strftime(timebuf, sizeof(timebuf), ".%Y%m%d-%H%M%S.", &tm);
    filename += timebuf;
    
    char pidbuf[32];
    snprintf(pidbuf, sizeof(pidbuf), "%d", getpid());  // 添加进程ID
    filename += pidbuf;
    
    filename += ".log";
    return filename;
}

void AsyncLogging::threadFunc() 
{
    assert(_running == true);
    
    // 创建两个新缓冲区用于后端处理
    BufferPtr newBuffer1(new LogBuffer(4*1024*1024));
    BufferPtr newBuffer2(new LogBuffer(4*1024*1024));
    
    // 用于存储待写入文件的缓冲区
    BufferVector buffersToWrite;
    buffersToWrite.reserve(16);
    
    // 打开日志文件
    time_t startTime = 0;
    std::string logFileName = getLogFileName(_basename, &startTime);

    // 使用标准模式打开文件，兼容更多系统
    FILE* file = fopen(logFileName.c_str(), "a");
    if (!file) 
    {
        // 记录文件打开失败的错误信息
        char errbuf[256];
        snprintf(errbuf, sizeof(errbuf), "Failed to open log file %s: %s\n", 
                logFileName.c_str(), strerror(errno));
        fprintf(stderr, "%s", errbuf);
        
        // 退回到标准输出
        file = stdout;  
    }
    
    while (_running) 
    {
        // 确保 newBuffer1 不为空且长度为 0
        if (!newBuffer1) {
            newBuffer1.reset(new LogBuffer(4*1024*1024));
        }
        if (newBuffer1->length() != 0) {
            newBuffer1->reset();
        }
        assert(newBuffer1 && newBuffer1->length() == 0);

        // 确保 newBuffer2 不为空且长度为 0
        if (!newBuffer2) {
            newBuffer2.reset(new LogBuffer(4*1024*1024));
        }
        if (newBuffer2->length() != 0) {
            newBuffer2->reset();
        }
        assert(newBuffer2 && newBuffer2->length() == 0);
        assert(buffersToWrite.empty());
        
        {
            // 等待数据或超时
            std::unique_lock<std::mutex> lock(_mutex);
            
            // 如果缓冲区队列为空，等待_flushInterval秒或被唤醒，并且没有强制刷新
            if (_buffers.empty() && !_flushRequest) 
            {
                _cond.wait_for(lock, std::chrono::seconds(_flushInterval));
            }
            
            // 将当前缓冲区加入待写入队列
            // 即使缓冲区未满，后端线程也会定期唤醒（如每 3 秒），将当前缓冲区的数据写入磁盘，确保日志的实时性。
            // 定时刷新：确保日志实时性
            // 防止数据丢失：应对系统崩溃
            if (_currentBuffer->length() > 0) 
            {
                _buffers.emplace_back(std::move(_currentBuffer));
            }
            
            // 重置当前缓冲区为newBuffer1
            _currentBuffer = std::move(newBuffer1);
            
            // 交换缓冲区队列，将待写入队列移到buffersToWrite
            if (!_buffers.empty()) 
            {
                buffersToWrite.swap(_buffers);
            }

            // 确保有预备缓冲区
            if (!_nextBuffer) 
            {
                _nextBuffer = std::move(newBuffer2);
            }

            // 处理刷新请求，这个时候已经把前端的缓冲队列交换到后端来了，可以看作处理完了
            if (_flushRequest) 
            {
                _flushRequest = false;      // 标记刷新完成
                _flushCond.notify_one();    // 唤醒所有等待的线程
            }
        }
        
        // 空队列时跳过处理
        if (buffersToWrite.empty()) { continue; }
        
        // 如果待写入缓冲区过多，丢弃部分（防止内存占用过大）
        if (buffersToWrite.size() > 25) 
        {
            // 记录丢弃信息
            char buf[256];
            snprintf(buf, sizeof(buf), "Dropped log messages at %s, %zd larger buffers\n",
                    __TIME__, buffersToWrite.size()-2);
            fwrite(buf, 1, strlen(buf), file);
            
            // 保留前两个缓冲区，丢弃前面的，保留最后两个，优先保留最新的日志
            buffersToWrite.erase(buffersToWrite.begin(), buffersToWrite.end() - 2);
        }
        
        // 将所有待写入缓冲区写入文件
        // 不会触发拷贝操作，所以不会和 unique_ptr 的特性产生冲突。
        for (const auto& buffer : buffersToWrite) 
        {
            if (buffer && buffer->length() > 0) 
            {
                size_t written = fwrite(buffer->data(), 1, buffer->length(), file);
                if (written != buffer->length()) 
                {
                    // 记录写入失败信息
                    char errbuf[256];
                    snprintf(errbuf, sizeof(errbuf), "Failed to write log to file: %s\n", 
                            strerror(errno));
                    fwrite(errbuf, 1, strlen(errbuf), file);
                }
            }
        }

        // 重置并复用缓冲区
        if (!buffersToWrite.empty()) 
        {
            if (!newBuffer1) 
            {
                newBuffer1 = std::move(buffersToWrite.back());
                newBuffer1->reset();
                buffersToWrite.pop_back();
            }
            
            if (!newBuffer2 && !buffersToWrite.empty()) 
            {
                newBuffer2 = std::move(buffersToWrite.back());
                newBuffer2->reset();
                buffersToWrite.pop_back();
            }
        }

        // 清空待写入队列
        buffersToWrite.clear();
        fflush(file);           // 单线程可定期刷盘，无需频繁fsync
        
        // 检查是否需要滚动日志文件
        time_t now = time(nullptr);
        bool needRoll = false;

        // 使用fstat替代ftell，支持大文件
        if (file != stdout) 
        {
            struct stat st;
            if (fstat(fileno(file), &st) == 0 && static_cast<size_t>(st.st_size) > _rollSize) 
            {
                needRoll = true;
            }
        }

        if (needRoll || now - startTime > 24*60*60)     // 每天或达到大小限制时滚动
        {  
            if (file != stdout) 
            {
                fclose(file);
            }
        
            logFileName = getLogFileName(_basename, &now);
            file = fopen(logFileName.c_str(), "a");
            if (!file) 
            {
                char errbuf[256];
                snprintf(errbuf, sizeof(errbuf), "Failed to open new log file %s: %s\n", 
                        logFileName.c_str(), strerror(errno));
                fprintf(stderr, "%s", errbuf);
                
                // 如果无法打开新文件，继续使用原文件或标准输出
                if (file == stdout) 
                {
                    // 已经在使用标准输出，无需处理
                } 
                else 
                {
                    // 尝试重新打开原文件
                    file = fopen(logFileName.c_str(), "a");
                    if (!file) 
                    {
                        file = stdout;
                    }
                }
            }
            startTime = now;  // 更新开始时间
        }  
    } // 线程循环结束

     // 处理程序退出前的残留数据
    {
        std::lock_guard<std::mutex> lock(_mutex);
        
        // 将当前缓冲区加入待写入队列（如果有数据）
        if (_currentBuffer->length() > 0) 
        {
            buffersToWrite.emplace_back(std::move(_currentBuffer));
        }
        
        // 将所有等待的缓冲区加入待写入队列
        if (!_buffers.empty()) 
        {
            for (auto& buffer : _buffers) 
            {
                if (buffer && buffer->length() > 0) 
                {
                    buffersToWrite.emplace_back(std::move(buffer));
                }
            }
            _buffers.clear();
        }
    }
    
    // 写入所有残留数据
    for (const auto& buffer : buffersToWrite) 
    {
        if (buffer && buffer->length() > 0) 
        {
            fwrite(buffer->data(), 1, buffer->length(), file);
        }
    }
    
    // 确保所有日志都被写入
    fflush(file);
    if (file != stdout) 
        fclose(file);
}

// Logger实现
Logger::Logger()
    : _asyncLogger(nullptr),
      _level(LogLevel::INFO) 
{ }

Logger::~Logger() 
{
    shutdown();  // 确保在析构时关闭日志系统
}

Logger& Logger::instance() 
{
    static Logger logger;  // 线程安全的静态局部变量
    return logger;
}

void Logger::init(const std::string& basename, size_t rollSize, int flushInterval) 
{
    // 允许重新初始化
    if (_asyncLogger) 
    {
        shutdown();
    }

    _asyncLogger.reset(new AsyncLogging(basename, rollSize, flushInterval));
    _asyncLogger->start();  // 启动异步日志线程
}

void Logger::log(LogLevel level, const char* file, int line, const char* func, const char* format, ...) 
{
    if (!_asyncLogger) 
    {
        return;  // 日志系统未初始化，直接返回
    }
    
    // 格式化时间戳
    char timebuf[32];
    struct timeval tv;
    time_t time;
    
    gettimeofday(&tv, nullptr); // 获取当前时间（秒+微秒）
    time = tv.tv_sec;
    struct tm tm;
    localtime_r(&time, &tm);    // 线程安全地转换为本地时间
    strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);   // 格式化年月日时分秒
    
    // 格式化日志级别
    const char* levelName = nullptr;
    switch (level) 
    {
        case LogLevel::TRACE: levelName = "TRACE"; break;
        case LogLevel::DEBUG: levelName = "DEBUG"; break;
        case LogLevel::INFO:  levelName = "INFO "; break;
        case LogLevel::WARN:  levelName = "WARN "; break;
        case LogLevel::ERROR: levelName = "ERROR"; break;
        case LogLevel::FATAL: levelName = "FATAL"; break;
    }
    
    // 格式化日志头（包含时间、级别、位置信息）
    char header[256];
    int headerLen = snprintf(header, sizeof(header),
                            "[%s.%06ld] [%s] [%s:%d %s] ",
                            timebuf, static_cast<long>(tv.tv_usec),     // 时间戳（含微秒）
                            levelName,                                  // 日志级别
                            file, line, func);                          // 代码位置（文件名:行号 函数名）
    
    // 格式化日志内容
    va_list args;
    va_start(args, format);
    
    char message[4096];
    int messageLen = vsnprintf(message, sizeof(message), format, args);
    
    va_end(args);
    
    // 合并日志头和内容
    char logline[4096 + 256];                           // 总大小 = 内容缓冲区 + 头缓冲区
    memcpy(logline, header, headerLen);                 // 复制日志头
    memcpy(logline + headerLen, message, messageLen);   // 复制日志内容
    int totalLen = headerLen + messageLen;
    
    // 补充换行符，保证每条日志独立一行
    if (totalLen < sizeof(logline) - 1) 
    {
        logline[totalLen] = '\n';
        totalLen++;
    }
    
    // 写入日志
    _asyncLogger->append(logline, totalLen);
}

void Logger::flush() 
{
    if (_asyncLogger) 
    {
        // 通过条件变量通知后端线程立即刷盘
        _asyncLogger->forceFlush();
    }
}

void Logger::shutdown() 
{
    if (_asyncLogger) 
    {
        _asyncLogger->forceFlush(); // 强制刷新所有日志数据
        _asyncLogger->stop();       // 停止异步日志线程
        _asyncLogger.reset();       // 释放资源
    }
}

} // namespace util